package com.huanledoudizhu.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.huanledoudizhu.controller.result.ResponseResult;
import com.huanledoudizhu.controller.result.ResultCode;
import com.huanledoudizhu.entity.RecycleBin;
import com.huanledoudizhu.entity.bean.Consts;
import com.huanledoudizhu.mapper.FileMapper;
import com.huanledoudizhu.mapper.RecycleBinMapper;
import com.huanledoudizhu.service.FileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huanledoudizhu.service.RecycleBinService;
import com.mchange.io.FileUtils;
import com.zaxxer.hikari.util.FastList;
import org.apache.ibatis.javassist.bytecode.stackmap.BasicBlock;
import org.json.JSONArray;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.huanledoudizhu.entity.File;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author huanledoudizhu
 * @since 2022-11-13
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {
    @Autowired
    FileMapper fileMapper;
    @Autowired
    RecycleBinMapper recycleBinMapper;

    public ResponseResult upload(MultipartFile file, String currentDirectory) throws IOException {
        if (file == null){
            return new ResponseResult(ResultCode.PARAM_IS_BLANK,"");
        }
        if (file.getSize() >= 2147483647){
            return new ResponseResult(ResultCode.FILE_EXCEEDS_SIZE);
        }
        String filename = file.getOriginalFilename();
        if (currentDirectory==null){
            currentDirectory="";
        }
        assert filename != null;
        if(filename.contains("\\")){//不同浏览器filename可能为名称可能为路径
            filename = filename.substring(filename.lastIndexOf("\\")+1);
        }
        //路径处理--------------
        String id = (String) StpUtil.getLoginId();
        String basepath = System.getProperty("user.dir");//获取项目路径
        String userPath = basepath + "\\src\\main\\resources\\file\\" +id;
        java.io.File path = new java.io.File(userPath);
        if (!path.exists()) {
            path.mkdirs();
        }
        String path2 = userPath + currentDirectory;//生成当前绝对路径
        //---------------------

        java.io.File f = new java.io.File(path2,filename);
        String fileType="";
        String name=filename;

        //可能有无后缀文件---------
        if (filename.contains(".")){
            fileType = filename.substring(filename.lastIndexOf(".")+1);
            name = filename.substring(0,filename.lastIndexOf("."));
        }
        //----------------------

        String namet = name;
        int i = 1;
        while (f.exists()){//相同文件名处理
            namet =  name+"("+i+")";
            f = new java.io.File(path,namet+fileType);
            i++;
        }
        String type = "未知";
        if (Consts.document.contains("."+fileType)) {
            type="文件";
        }
        else if (Consts.picture.contains("."+fileType)) {
            type="图片";
        }
        else if (Consts.video.contains("."+fileType)) {
            type="视频";
        }
        else if (Consts.audio.contains("."+fileType)) {
            type="音频";
        }
        else if (Consts.compress.contains("."+fileType)) {
            type="压缩包";
        }


        File file1 = new File();
        file1.setFileName(namet);
        file1.setFileSize((int)file.getSize());
        String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
        file1.setFileMd5(md5);
        file1.setFileExtension(fileType);
        file1.setFileType(type);
        file1.setFileLocation(path2);
        this.save(file1);
        file.transferTo(f);//MaxUploadSizeExceededException 会删除临时文件夹
        return new ResponseResult(ResultCode.SUCESS,file1);
    }


    public ResponseResult download(int id,  HttpServletResponse httpServletResponse, HttpServletRequest httpServletRequest) throws IOException {
        File file = this.getById(id);
        String path = file.getFileLocation();
        String extension = file.getFileExtension();
        String fileName = file.getFileName()+"."+extension;
        if (path!=null||!path.equals("")){
            FileInputStream fileInputStream = new FileInputStream(new java.io.File(path,fileName));
            httpServletResponse.setContentType(httpServletRequest.getSession().getServletContext().getMimeType(extension));//获取文件的mimetype
            httpServletResponse.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));
            ServletOutputStream os = httpServletResponse.getOutputStream();
            FileCopyUtils.copy(fileInputStream,os);
            return new ResponseResult(ResultCode.SUCESS,file);
        }
        return new ResponseResult(ResultCode.FAILURE);
    }

    public ResponseResult delete(List<Integer> checkbox) throws JSONException {
        for (Integer integer : checkbox) {
            File file = this.getById(integer);
            System.out.println(integer);
            if (file.getIsDir() == 1) {
                deleteDirSql(integer, Integer.parseInt((String) StpUtil.getLoginId()), file);//删除所有子文件
                deleteDirRecycle(integer, Integer.parseInt((String) StpUtil.getLoginId()), file);//删除回收站这个文件夹下的所有子文件
                java.io.File f = new java.io.File(file.getFileLocation());
                deleteDir(f);//物理删除
            } else {
                fileMapper.deleteByIdWhereCreatorId(integer, Integer.parseInt((String) StpUtil.getLoginId()));//删除本文件
                java.io.File f = new java.io.File(file.getFileLocation(), file.getFileName() + "." + file.getFileExtension());
                f.delete();
            }
        }
        return new ResponseResult(ResultCode.SUCESS);
    }




    public void deleteDir(java.io.File dir){
        if (dir.isDirectory()){
            String[] children = dir.list();
            for (int i = 0; i < children.length;i++){
                deleteDir(new java.io.File(dir,children[i]));
            }
        }
        dir.delete();
    }

    public void deleteDirSql(int id, int userId, File dir){
        List<File> fileList = fileMapper.getByCreatorId(userId);
        for (File file : fileList) {
            String l = file.getFileLocation();
            if (l.contains(dir.getFileLocation())&&(l.substring(dir.getFileLocation().length()).equals("") || l.substring(dir.getFileLocation().length()).charAt(0)=='\\')) {
                fileMapper.deleteById(file.getId());
            }
        }
    }

    public void deleteDirRecycle(int id, int userId, File dir){
        List<RecycleBin> recycleBinList = recycleBinMapper.getByCreatorId(userId);
        for (RecycleBin recycleBin : recycleBinList) {
            String l = recycleBin.getFileLocation();
            if (l.contains(dir.getFileLocation())&&(l.substring(dir.getFileLocation().length()).equals("") || l.substring(dir.getFileLocation().length()).charAt(0)=='\\')) {
                recycleBinMapper.deleteById(recycleBin.getId());
            }
        }
    }


    public ResponseResult createDir(String dirName, String currentDirectory){
        if (currentDirectory==null){
            currentDirectory = "";
        }
        if (dirName==null){
            return new ResponseResult(ResultCode.PARAM_IS_INVALID);
        }
        String id = (String) StpUtil.getLoginId();
        String basepath = System.getProperty("user.dir");
        String path = basepath + "\\src\\main\\resources\\file\\"+ id + currentDirectory + "\\" +dirName;
        java.io.File d = new java.io.File(path);
        if(!d.exists()){
            if (d.mkdir()==false){
                return new ResponseResult(ResultCode.FAILURE);//父目录不存在
            }
            File f = new File();
            f.setFileName(dirName);
            f.setFileLocation(path);
            f.setIsDir(1);
            this.save(f);
            return new ResponseResult(ResultCode.SUCESS,f);
        }
        return new ResponseResult(ResultCode.FAILURE);//目录存在
    }

    public ResponseResult modifyFileName(int id, String fileName, String currentDirectory) throws IOException {
        if (fileName==null||fileName.equals("")){
            return new ResponseResult(ResultCode.PARAM_IS_INVALID);
        }
        File f = this.getById(id);
        if(f.getIsDir()==1&&fileName.contains(".")){
            return new ResponseResult(ResultCode.PARAM_IS_INVALID);
        }
        String fileType="";
        String name=fileName;

        //可能有无后缀文件---------
        if (fileName.contains(".")){
            fileType = fileName.substring(fileName.lastIndexOf(".")+1);
            name = fileName.substring(0,fileName.lastIndexOf("."));
        }
        String path = f.getFileLocation();
        String extension = f.getFileExtension();
        java.io.File ff=null;
        java.io.File ff2=null;
        String path2 = path;
        if (f.getIsDir()==1){
            if (!fileName.matches("[0-9a-zA-Z_]+")){//校验能否为文件夹名称
                return new ResponseResult(ResultCode.PARAM_IS_INVALID);
            }
            path2 = path.substring(0,path.lastIndexOf("\\")+1)+fileName;
            ff = new java.io.File(path);
            ff2 = new java.io.File(path2);
            if (ff2.exists()){
                return new ResponseResult(ResultCode.PARAM_IS_INVALID);//文件夹名称重复
            }
            ff2.mkdir();
            this.copy(ff,ff2);
            this.updateLocation(path,path2);
            this.deleteDir(ff);
        }
        String type = "未知";
        if (f.getIsDir()==0){
            if (!fileName.matches("^[A-Za-z0-9]([A-z0-9._]?)+")){//校验能否为文件名称
                return new ResponseResult(ResultCode.PARAM_IS_INVALID);
            }
            String fileNamep = f.getFileName()+"."+extension;
            ff = new java.io.File(path,fileNamep);
            ff2 = new java.io.File(path,fileName);

            if (Consts.document.contains("."+fileType)) {
                type="文件";
            }
            else if (Consts.picture.contains("."+fileType)) {
                type="图片";
            }
            else if (Consts.video.contains("."+fileType)) {
                type="视频";
            }
            else if (Consts.audio.contains("."+fileType)) {
                type="音频";
            }
            else if (Consts.compress.contains("."+fileType)) {
                type="压缩包";
            }

        }
        ff.renameTo(ff2);
        if (fileMapper.UpdateFileNameAndFileExtensionById(name, fileType, path2, type, id)){
            return new ResponseResult(ResultCode.SUCESS);
        }
        return new ResponseResult(ResultCode.FAILURE);
    }

    public static void copy(java.io.File src, java.io.File des) {
        java.io.File[] fileArray = src.listFiles();
        if(fileArray != null) {
            for(java.io.File src1 : fileArray) {
                java.io.File des1 = new java.io.File(des, src1.getName());
                if(src1.isDirectory()) {
                    des1.mkdir();
                    copy(src1, des1);
                }else {
                    write(src1, des1);
                }
            }
        }
    }

    public static void write(java.io.File src, java.io.File des) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(src);
            fos = new FileOutputStream(des);
            byte[] bys = new byte[1024];
            int len = 0;
            while((len = fis.read(bys)) != -1) {
                fos.write(bys, 0, len);
            }
        }catch(FileNotFoundException e) {
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally {
            try {
                fis.close();
                fos.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

    Boolean updateLocation(String location, String newLocation){
        List<File> fileList = fileMapper.getByCreatorId(Integer.parseInt((String) StpUtil.getLoginId()));
        for (File file : fileList) {
            String l = file.getFileLocation();
            if (l.contains(location)&&(l.substring(location.length()).equals("") || l.substring(location.length()).charAt(0)=='\\')) {
                fileMapper.UpdateFileLocationByFileId(newLocation + l.substring(location.length()), file.getId());
            }
        }
        return true;
    }

    public ResponseResult currentDirectory(String currentDirectory){
        if (currentDirectory==null){
            currentDirectory="";
        }
        int id = Integer.parseInt((String) StpUtil.getLoginId());
        String basepath = System.getProperty("user.dir");
        String path = basepath + "\\src\\main\\resources\\file\\"+ id + currentDirectory;
        List<File> fileList = fileMapper.getByCreatorId(id);
        List<File> fileList1 = new ArrayList<>();
        for (File file : fileList) {
            String l = file.getFileLocation();
            if (l.contains(path)&&file.getIsDir()==0&&!(l.substring(path.length()).contains("\\"))) {
                fileList1.add(file);
            }
            if (l.contains(path+"\\")&&file.getIsDir()==1&&!(l.substring((path+"\\").length()).contains("\\"))) {
                fileList1.add(file);
            }
        }
        return new ResponseResult(ResultCode.SUCESS,fileList1);
    }

    public ResponseResult classification(String s){
        if (s==null||s.equals("")){
            return new ResponseResult(ResultCode.PARAM_IS_INVALID);
        }
        return new ResponseResult(ResultCode.SUCESS, fileMapper.getByFileType(s, Integer.parseInt((String) StpUtil.getLoginId())));
    }
}
